package org.jsola.hr.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.response.AlipayUserAgreementQueryResponse;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import lombok.extern.slf4j.Slf4j;
import org.jsola.admin.vo.SiteVO;
import org.jsola.common.CollectionKit;
import org.jsola.common.DateKit8;
import org.jsola.common.StrKit;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.NumberKit;
import org.jsola.hr.common.oneKeyPay.AliSafetyPay;
import org.jsola.hr.common.oneKeyPay.PingAnBankPay;
import org.jsola.hr.common.oneKeyPay.VXpayClear;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.constant.TransferAccountsTypeEnum;
import org.jsola.hr.core.HrOneKeyPayProperties;
import org.jsola.hr.dao.ITransferAccountInfoDAO;
import org.jsola.hr.dto.TransferAccountInfoAddDTO;
import org.jsola.hr.dto.TransferAccountInfoUpdateDTO;
import org.jsola.hr.entity.TransferAccountInfoDO;
import org.jsola.hr.provider.ISiteConfigProviderService;
import org.jsola.hr.provider.ISiteProviderService;
import org.jsola.hr.query.TransferAccountInfoQuery;
import org.jsola.hr.service.ITransferAccountInfoService;
import org.jsola.hr.service.ITransferAccountsBatchService;
import org.jsola.hr.vo.TransferAccountInfoListVO;
import org.jsola.hr.vo.TransferAccountInfoVO;
import org.jsola.hr.vo.payAli.safetyPay.AccountBookQueryVO;
import org.jsola.hr.vo.payPingAn.PingAnBankSelectAccountInfoVO;
import org.jsola.hr.vo.payWx.VxBuildUserToken;
import org.jsola.hr.vo.payWx.VxConfigVO;
import org.jsola.hr.vo.payWx.VxReturnAccountInfoVO;
import org.jsola.hr.vo.payWx.VxWgkUserAuthResultVO;
import org.jsola.hr.vo.payWx.checkFace.VxCheckFaceReturnVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 转账账户库
 *
 * @author zhr
 */
@Service("hrTransferAccountInfoServiceImpl")
@Slf4j
public class TransferAccountInfoServiceImpl implements ITransferAccountInfoService {

    @Autowired
    private ITransferAccountInfoDAO transferAccountInfoDAO;
    @Autowired
    private ITransferAccountsBatchService transferAccountsBatchService;

    @Autowired
    private ISiteProviderService siteProviderService;
    @Autowired
    private ISiteConfigProviderService siteConfigProviderService;

    @Autowired
    private HrOneKeyPayProperties hrOneKeyPayProperties;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public TransferAccountInfoVO save(TransferAccountInfoAddDTO transferAccountInfoAddDTO, TokenUser tokenUser) {
        // 校验该名称是否在该租户存在
        String name = transferAccountInfoAddDTO.getName();
        if (StrKit.isEmpty(name)) {
            throw new ParamException("账户名称不能为空！");
        }
        List<TransferAccountInfoDO> transferAccountInfoDOList = this.selectByName(tokenUser.getSiteId(), name);
        if (CollectionKit.isNotEmpty(transferAccountInfoDOList)) {
            throw new ParamException("账户名称不能重复！");
        }
        SiteVO siteVO = siteProviderService.selectById(tokenUser.getSiteId(), tokenUser.getSiteId());
        ParamException.notNull(siteVO, "该租户已被删除,无法添加!");
        transferAccountInfoAddDTO.setSiteName(siteVO.getName());
        // 如果类型是微信，则校验是否存在微信账户，存在则不允许添加
        if (TransferAccountsTypeEnum.VX.getValue().equals(transferAccountInfoAddDTO.getType())) {
            if (CollectionKit.isNotEmpty(this.selectListByType(TransferAccountsTypeEnum.VX.getValue(), tokenUser.getSiteId()))) {
                throw new ParamException("一个租户只允许添加一个微信发放账户，请删除后重试！");
            }
        }
        // 转DO
        TransferAccountInfoDO transferAccountInfoDO = transferAccountInfoAddDTO.to(TransferAccountInfoDO.class);
        // 保存
        transferAccountInfoDO = save(transferAccountInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return transferAccountInfoDO.to(TransferAccountInfoVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(TransferAccountInfoUpdateDTO transferAccountInfoUpdateDTO, TokenUser tokenUser) {
        //转DO
        TransferAccountInfoDO transferAccountInfoDO = transferAccountInfoUpdateDTO.to(TransferAccountInfoDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(transferAccountInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... transferAccountInfoIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) transferAccountInfoIds);
    }


    @Override
    public TransferAccountInfoVO selectById(String transferAccountInfoId, String siteId) {
        TransferAccountInfoDO transferAccountInfoDO = selectDOById(transferAccountInfoId, siteId);
        if (transferAccountInfoDO == null) {
            return null;
        }
        return transferAccountInfoDO.to(TransferAccountInfoVO.class);
    }

    @Override
    public List<TransferAccountInfoListVO> select(TransferAccountInfoQuery transferAccountInfoQuery, String siteId) {
        List<TransferAccountInfoDO> transferAccountInfoDOList = selectDO(transferAccountInfoQuery, siteId);
        if (CollectionUtils.isEmpty(transferAccountInfoDOList)) {
            return transferAccountInfoDOList == null ? null : new ArrayList<>();
        }
        return transferAccountInfoDOList.stream()
                .map(transferAccountInfoDO -> transferAccountInfoDO.to(TransferAccountInfoListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(TransferAccountInfoQuery transferAccountInfoQuery, String siteId) {
        Example example = buildExample(transferAccountInfoQuery, siteId);
        return transferAccountInfoDAO.selectCountByExample(example);
    }

    @Override
    public Page<TransferAccountInfoListVO> selectPage(TransferAccountInfoQuery transferAccountInfoQuery, String siteId) {
        Example example = buildExample(transferAccountInfoQuery, siteId);
        Page<TransferAccountInfoDO> page = transferAccountInfoDAO.selectPageByExample(example,
                transferAccountInfoQuery.getPageNo(),
                transferAccountInfoQuery.getPageSize());

        return page.to(TransferAccountInfoListVO.class);
    }

    @Override
    public TransferAccountInfoDO selectDOById(String transferAccountInfoId, String siteId) {
        return listById(transferAccountInfoId, siteId);
    }

    @Override
    public List<TransferAccountInfoDO> selectDO(TransferAccountInfoQuery transferAccountInfoQuery, String siteId) {
        Example example = buildExample(transferAccountInfoQuery, siteId);
        return transferAccountInfoDAO.selectByExample(example);
    }

    @Override
    public List<TransferAccountInfoDO> selectBySiteIdAndType(String siteId, Integer type) {
        if (StrKit.isEmpty(siteId) || type == null) {
            throw new ParamException("必传参数未填写！");
        }
        Example example = new Example(TransferAccountInfoDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("valid", true)
                .andEqualTo("type", type);
        return transferAccountInfoDAO.selectByExample(example);
    }

    @Override
    public List<TransferAccountInfoDO> selectByName(String siteId, String name) {
        if (StrKit.isEmpty(siteId) || name == null) {
            throw new ParamException("必传参数未填写！");
        }
        Example example = new Example(TransferAccountInfoDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("valid", true)
                .andEqualTo("name", name);
        return transferAccountInfoDAO.selectByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<TransferAccountInfoVO> selectVxAccountMoney(String siteId) {
        List<TransferAccountInfoVO> transferAccountInfoVOList = new ArrayList<>();
        // 查询该租户的微信账户信息
        List<TransferAccountInfoDO> transferAccountInfoDOList = this
                .selectBySiteIdAndType(siteId, TransferAccountsTypeEnum.VX.getValue());
        if (CollectionUtils.isEmpty(transferAccountInfoDOList)) {
            return transferAccountInfoVOList;
        }
        // 获取微信服务商全部的配置信息
        VxConfigVO vxConfigVO = transferAccountsBatchService.selectVxConfigVO(siteId);
        for (TransferAccountInfoDO transferAccountInfoDO : transferAccountInfoDOList) {
            // 拼接get的URL
            String url = "https://api.mch.weixin.qq.com/v3/ecommerce/fund/balance/" +
                    transferAccountInfoDO.getSubMchid() +
                    "?account_type=OPERATION";
            // 获取微信请求头的Authorization
            String authorization = VXpayClear.generateAuthorization("", "GET", url,
                    vxConfigVO.getSpMchid(), vxConfigVO.getCertificateSerialNo(), vxConfigVO.getPrivateKeyPath());
            // 调用微信查询余额接口，查询各个账户的余额 并且修改余额
            String vxReturnStr = VXpayClear.vxSelectTransferAccountsInfo(url, authorization,
                    vxConfigVO.getWechatpaySerial());
            VxReturnAccountInfoVO vxReturnAccountInfoVO = JSON.parseObject(vxReturnStr, VxReturnAccountInfoVO.class);
            if (vxReturnAccountInfoVO.getAvailableAmount() == null) {
                log.error("查询微信账户余额失败，微信返回结果：{}", vxReturnStr);
                throw new ParamException("查询微信账户余额失败，请联系管理员查询原因。");
            }
            BigDecimal money = NumberKit.pareMoneyFromFenToYuan(vxReturnAccountInfoVO.getAvailableAmount(),
                    2, BigDecimal.ROUND_DOWN);
            transferAccountInfoDO.setMoney(money);
            transferAccountInfoVOList.add(transferAccountInfoDO.to(TransferAccountInfoVO.class));
            // 修改数据库里的余额
            this.updateByIdSelective(transferAccountInfoDO);
        }
        transferAccountInfoVOList = transferAccountInfoVOList.stream()
                .sorted(Comparator.comparing(TransferAccountInfoVO::getMoney).reversed()).collect(Collectors.toList());
        return transferAccountInfoVOList;
    }

    @Override
    public TransferAccountInfoDO selectBySiteIdAndAccount(Integer type, String account, String siteId) {
        if (StrKit.isEmpty(siteId) || type == null || StrKit.isEmpty(account)) {
            throw new ParamException("必传参数未填写！");
        }
        Example example = new Example(TransferAccountInfoDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("valid", true);
        if (TransferAccountsTypeEnum.ZFB.getValue().equals(type)) {
            example.and()
                    .andEqualTo("zfbPid", account);
        } else if (TransferAccountsTypeEnum.VX.getValue().equals(type)) {
            example.and()
                    .andEqualTo("subMchid", account);
        } else if (TransferAccountsTypeEnum.BANK.getValue().equals(type)) {
            example.and()
                    .andEqualTo("bankAccountId", account);
        } else if (TransferAccountsTypeEnum.ZFB_SAFETY.getValue().equals(type)) {
            example.and()
                    .andEqualTo("zfbAccountBookId", account);
        } else {
            throw new ParamException("类型不合法！请重新传入");
        }
        return transferAccountInfoDAO.selectOneByExample(example);
    }

    @Override
    public TransferAccountInfoDO selectByTypeAndAccount(Integer type, String account) {
        if (type == null || StrKit.isEmpty(account)) {
            throw new ParamException("必传参数未填写！");
        }
        Example example = new Example(TransferAccountInfoDO.class);
        example.and()
                .andEqualTo("valid", true);
        if (TransferAccountsTypeEnum.ZFB.getValue().equals(type)) {
            example.and()
                    .andEqualTo("zfbPid", account);
        } else if (TransferAccountsTypeEnum.VX.getValue().equals(type)) {
            example.and()
                    .andEqualTo("subMchid", account);
        } else if (TransferAccountsTypeEnum.BANK.getValue().equals(type)) {
            example.and()
                    .andEqualTo("bankAccountId", account);
        } else if (TransferAccountsTypeEnum.ZFB_SAFETY.getValue().equals(type)) {
            example.and()
                    .andEqualTo("zfbAccountBookId", account);
        } else {
            throw new ParamException("类型不合法！请重新传入");
        }
        return transferAccountInfoDAO.selectOneByExample(example);
    }

    @Override
    public String generateZfbSignUrl(String loginId) {
        if (StrKit.isEmpty(loginId)) {
            throw new ParamException("支付宝登录账号为空, 无法生成签约链接！");
        }
        CertAlipayRequest certAlipayRequest = transferAccountsBatchService.buildCertAlipaySafetyRequest();
        return AliSafetyPay.createUrl(certAlipayRequest, loginId);
    }

    @Override
    public String generateZfbSafetyPayAccountBook(String transferAccountInfoId, TokenUser tokenUser) {
        if (StrKit.isEmpty(transferAccountInfoId)) {
            throw new ParamException("id不能为空!");
        }
        Example example = new Example(TransferAccountInfoDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("id", transferAccountInfoId);
        TransferAccountInfoDO transferAccountInfoDO = transferAccountInfoDAO.selectOneByExample(example);
        ParamException.notNull(transferAccountInfoDO, "该条记录不存在或已删除，请刷新重试！");
        if (StrKit.isEmpty(transferAccountInfoDO.getZfbLoginId())) {
            throw new ParamException("支付宝登录账号为空，无法生成记账本!");
        }
        String loginId = transferAccountInfoDO.getZfbLoginId();
        CertAlipayRequest certAlipayRequest = transferAccountsBatchService.buildCertAlipaySafetyRequest();
        // 根据 签约号 获取 协议号;   参数：1: 公共参数 2: 签约号(生成的签约号默认是登录账号)
        AlipayUserAgreementQueryResponse alipayUserAgreementQueryResponse = AliSafetyPay.selectAgreementNo(certAlipayRequest, loginId);
        String agreementNo = alipayUserAgreementQueryResponse.getAgreementNo();
        // 开通 单笔转账到户的 记账本;   参数：1: 公共参数 2: 支付宝登录账号 3: 协议号
        String accountBookId = AliSafetyPay.createAccountBook(certAlipayRequest, loginId, agreementNo);
        // 修改账户表的记账本id
        transferAccountInfoDO.setZfbAccountBookId(accountBookId);
        transferAccountInfoDO.setMoney(new BigDecimal("0"));
        this.updateById(transferAccountInfoDO, transferAccountInfoDO.getSiteId(), tokenUser.getUserId());
        return accountBookId;
    }

    @Override
    public List<TransferAccountInfoVO> selectZfbSafetyAccountMoney(String siteId) {
        List<TransferAccountInfoVO> transferAccountInfoVOList = new ArrayList<>();
        // 查询该租户的支付宝安全发账户信息
        List<TransferAccountInfoDO> transferAccountInfoDOList = this
                .selectBySiteIdAndType(siteId, TransferAccountsTypeEnum.ZFB_SAFETY.getValue());
        if (CollectionUtils.isEmpty(transferAccountInfoDOList)) {
            return transferAccountInfoVOList;
        }
        // 过滤没有记账本id 的账户
        transferAccountInfoDOList.removeIf(transferAccountInfoDO -> {
            if (StrKit.isEmpty(transferAccountInfoDO.getZfbAccountBookId())) {
                return true;
            }
            return StrKit.isEmpty(transferAccountInfoDO.getZfbLoginId());
        });
        if (CollectionUtils.isEmpty(transferAccountInfoDOList)) {
            return transferAccountInfoVOList;
        }
        CertAlipayRequest certAlipayRequest = transferAccountsBatchService.buildCertAlipaySafetyRequest();
        for (TransferAccountInfoDO transferAccountInfoDO : transferAccountInfoDOList) {
            // 根据 签约号 获取 协议号;   参数：1: 公共参数 2: 签约号(生成的签约号默认是登录账号)
            AlipayUserAgreementQueryResponse alipayUserAgreementQueryResponse = AliSafetyPay
                    .selectAgreementNo(certAlipayRequest, transferAccountInfoDO.getZfbLoginId());
            String agreementNo = alipayUserAgreementQueryResponse.getAgreementNo();
            AccountBookQueryVO accountBookQueryVO = AliSafetyPay.selectAccountBook(certAlipayRequest,
                    transferAccountInfoDO.getZfbAccountBookId(), agreementNo);
            transferAccountInfoDO.setMoney(new BigDecimal(accountBookQueryVO.getAvailableAmount()));
            transferAccountInfoVOList.add(transferAccountInfoDO.to(TransferAccountInfoVO.class));
            // 修改数据库里的余额
            this.updateByIdSelective(transferAccountInfoDO);
        }
        transferAccountInfoVOList = transferAccountInfoVOList.stream()
                .sorted(Comparator.comparing(TransferAccountInfoVO::getMoney).reversed()).collect(Collectors.toList());
        return transferAccountInfoVOList;
    }

    @Override
    public String generateZfbMoneyToBookUrl(String transferAccountInfoId, Double money, TokenUser tokenUser) {
        if (StrKit.isEmpty(transferAccountInfoId)) {
            throw new ParamException("id不能为空!");
        }
        ParamException.notNull(money, "充值金额不能为空!");
        Example example = new Example(TransferAccountInfoDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("id", transferAccountInfoId);
        TransferAccountInfoDO transferAccountInfoDO = transferAccountInfoDAO.selectOneByExample(example);
        ParamException.notNull(transferAccountInfoDO, "该条记录不存在或已删除，请刷新重试！");
        if (StrKit.isEmpty(transferAccountInfoDO.getZfbLoginId())
                || StrKit.isEmpty(transferAccountInfoDO.getZfbAccountBookId())) {
            throw new ParamException("支付宝登录账号为空或记账本id为空，无法生成付款链接，请确认后重试!");
        }
        String loginId = transferAccountInfoDO.getZfbLoginId();
        CertAlipayRequest certAlipayRequest = transferAccountsBatchService.buildCertAlipaySafetyRequest();
        // 根据 签约号 获取 协议号;   参数：1: 公共参数 2: 签约号(生成的签约号默认是登录账号)
        AlipayUserAgreementQueryResponse alipayUserAgreementQueryResponse = AliSafetyPay.selectAgreementNo(certAlipayRequest, loginId);
        String agreementNo = alipayUserAgreementQueryResponse.getAgreementNo();
        return AliSafetyPay.transferToBook(certAlipayRequest, transferAccountInfoDO.getZfbAccountBookId(),
                agreementNo, money);
    }

    @Override
    public List<TransferAccountInfoDO> selectListByType(Integer type, String siteId) {
        if (type == null) {
            throw new ParamException("类型不能为空!");
        }
        Example example = new Example(TransferAccountInfoDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("valid", true)
                .andEqualTo("type", TransferAccountsTypeEnum.VX.getValue());
        return transferAccountInfoDAO.selectByExample(example);
    }

    @Override
    public VxWgkUserAuthResultVO selectUserAuthStatus(String openId, String siteId) {
        if (StrKit.isEmpty(openId) || StrKit.isEmpty(siteId)) {
            throw new ParamException("openid或siteId为空，请求失败！");
        }
        // 查询该租户的微信发放账户的 特约商户商户号
        List<TransferAccountInfoDO> transferAccountInfoDOList = this
                .selectListByType(TransferAccountsTypeEnum.VX.getValue(), siteId);
        if (CollectionKit.isEmpty(transferAccountInfoDOList)) {
            log.error("微信发放账户不存在，请先添加发放账户！租户id:{}", siteId);
            return null;
        }
        TransferAccountInfoDO transferAccountInfoDO = transferAccountInfoDOList.get(0);
        if (StrKit.isEmpty(transferAccountInfoDO.getSubMchid())) {
            log.error("微信发放账户的商户号为空，无法查询授权状态！租户id:{}", siteId);
            return null;
        }
        // 获取微信服务商全部的配置信息
        VxConfigVO vxConfigVO = transferAccountsBatchService.selectVxConfigVO(siteId);
        // 拼接get的URL
        String url = "https://api.mch.weixin.qq.com/v3/payroll-card/relations/" +
                openId +
                "?sub_mchid="+ transferAccountInfoDO.getSubMchid() +
                "&appid=" + vxConfigVO.getSpAppid();
        // 获取微信请求头的Authorization
        String authorization = VXpayClear.generateAuthorization("", "GET", url,
                vxConfigVO.getSpMchid(), vxConfigVO.getCertificateSerialNo(), vxConfigVO.getPrivateKeyPath());
        HttpResponse<String> socResponse = Unirest.get(url)
                .header("Content-Type", "application/json")
                .header("Authorization", authorization)
                .header("User-Agent", "zhixinren/1.0")
                .header("Accept", "*/*")
                .header("Wechatpay-Serial", vxConfigVO.getWechatpaySerial()).asString();
        if (socResponse.isSuccess()) {
            VxWgkUserAuthResultVO vxWgkUserAuthResultVO = JSONObject
                    .parseObject(socResponse.getBody(), VxWgkUserAuthResultVO.class);
            vxWgkUserAuthResultVO.setSpAppId(vxConfigVO.getSpAppid());
            return vxWgkUserAuthResultVO;
        } else {
            log.error("查询微工卡授权结果失败, 请求参数：{}, 微信返回结果：{}", url, socResponse.getBody());
            throw new ParamException("查询微工卡授权结果失败，请联系管理员！" + socResponse.getBody());
        }
    }

    @Override
    public VxCheckFaceReturnVO buildAuthToken(VxBuildUserToken vxBuildUserToken, String siteId) {
        // 查询该租户的微信发放账户的 特约商户商户号
        List<TransferAccountInfoDO> transferAccountInfoDOList = this
                .selectListByType(TransferAccountsTypeEnum.VX.getValue(), siteId);
        if (CollectionKit.isEmpty(transferAccountInfoDOList)) {
            throw new ParamException("微信发放账户不存在，请先添加发放账户！");
        }
        TransferAccountInfoDO transferAccountInfoDO = transferAccountInfoDOList.get(0);
        if (StrKit.isEmpty(transferAccountInfoDO.getSubMchid())) {
            throw new ParamException("微信发放账户的商户号为空，无法查询授权状态！");
        }
        String userName = vxBuildUserToken.getUserName();
        String idCardNumber = vxBuildUserToken.getIdCardNumber();
        String openId = vxBuildUserToken.getOpenid();
        if (StrKit.isEmpty(userName) || StrKit.isEmpty(idCardNumber) || StrKit.isEmpty(openId)) {
            throw new ParamException("用户实名、用户证件号、openId都不能为空");
        }
        // 获取微信服务商全部的配置信息
        VxConfigVO vxConfigVO = transferAccountsBatchService.selectVxConfigVO(siteId);
        // 设置固定的值
        String employmentType = "LONG_TERM_EMPLOYMENT";
        // 设置body的值
        vxBuildUserToken.setOpenid(openId);
        vxBuildUserToken.setAppid(vxConfigVO.getSpAppid());
        vxBuildUserToken.setSubMchid(transferAccountInfoDO.getSubMchid());
        vxBuildUserToken.setUserName(VXpayClear.rsaEncryptOAEP(userName, vxConfigVO.getVxCertificate()));
        vxBuildUserToken.setIdCardNumber(VXpayClear.rsaEncryptOAEP(idCardNumber, vxConfigVO.getVxCertificate()));
        vxBuildUserToken.setEmploymentType(employmentType);
        // 调用微信微工卡 生成授权token
        String authorization = VXpayClear.generateAuthorization(JSON.toJSONString(vxBuildUserToken), "POST",
                "https://api.mch.weixin.qq.com/v3/payroll-card/tokens",
                vxConfigVO.getSpMchid(), vxConfigVO.getCertificateSerialNo(), vxConfigVO.getPrivateKeyPath());
        VxCheckFaceReturnVO vxCheckFaceReturnVO = VXpayClear.vxBuildAuthToken(vxBuildUserToken, authorization, vxConfigVO.getWechatpaySerial());
        vxCheckFaceReturnVO.setAppid(vxConfigVO.getSpAppid());
        return vxCheckFaceReturnVO;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<TransferAccountInfoVO> selectPingAnBankAccountMoney(String siteId) {
        List<TransferAccountInfoVO> transferAccountInfoVOList = new ArrayList<>();
        // 查询该租户的微信账户信息
        List<TransferAccountInfoDO> transferAccountInfoDOList = this
                .selectBySiteIdAndType(siteId, TransferAccountsTypeEnum.BANK.getValue());
        if (CollectionUtils.isEmpty(transferAccountInfoDOList)) {
            return transferAccountInfoVOList;
        }
        for (TransferAccountInfoDO transferAccountInfoDO : transferAccountInfoDOList) {
            if (StrKit.isEmpty(transferAccountInfoDO.getBankAccountId())
                    || StrKit.isEmpty(transferAccountInfoDO.getCompanyCode())
                    || StrKit.isEmpty(transferAccountInfoDO.getAgreeNo())
                    || StrKit.isEmpty(transferAccountInfoDO.getBusiType())) {
                // 有一个参数为填写 则不需要调用查询余额
                continue;
            }
            try {
                // 构造请求报文头
                String xmlStr = "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
                        "<Result>" +
                        "<Account>" + transferAccountInfoDO.getBankAccountId() + "</Account>" +
                        "<AgreeNo>" + transferAccountInfoDO.getAgreeNo() + "</AgreeNo>" +
                        "</Result>";
                HrOneKeyPayProperties.PingAn pingAn = hrOneKeyPayProperties.getPingAn();
                String messageLength = String.format("%010d", xmlStr.getBytes("GBK").length);
//                String dealCode = "4001  ";
                String dealCode = "404705";
                String serveType = "01";
                Date date = new Date();
                String dealDate = DateKit8.format(date, "yyyyMMdd");
                String dealTime = DateKit8.format(date, "HHmmss");
                String systemSerialNumber = PingAnBankPay.getGuid();
                String requestHeader = pingAn.getMessageType() + pingAn.getTargetSystemNumber() +
                        pingAn.getMessageEncoder() + pingAn.getMessageAgreement() +
                        transferAccountInfoDO.getCompanyCode() + messageLength + dealCode + pingAn.getOperatorCode() +
                        serveType + dealDate + dealTime + systemSerialNumber +
                        "0000000000000000000000000000000000000000000000000000000000000000000000000000000" +
                        "00000000000000000000000000000000000000000000000000000000";
                String returnStr = PingAnBankPay.tcpPost("127.0.0.1", 7073, requestHeader + xmlStr);
                log.info("查询平安银行账户余额返回结果:{},===入参:{}", returnStr, requestHeader + xmlStr);
                int systemSerialNumberIndex = returnStr.indexOf(systemSerialNumber) + systemSerialNumber.length();
                if (!returnStr.contains("<?xml") ||
                        !"000000".equals(returnStr.substring(systemSerialNumberIndex, systemSerialNumberIndex + 6))) {
                    log.error("查询平安银行账户余额查询失败:{},===入参:{}", returnStr, requestHeader + xmlStr);
                    // 查询失败
                    throw new ParamException("查询平安银行账户余额查询失败，银行返回信息:" + returnStr);
                }
                returnStr = returnStr.substring(returnStr.indexOf("<?xml"));
                PingAnBankSelectAccountInfoVO pingAnBankSelectBatchVO = PingAnBankPay.converyToPingAnBankSelectAccountInfoVO(returnStr,
                        PingAnBankSelectAccountInfoVO.class);
                BigDecimal money = new BigDecimal(pingAnBankSelectBatchVO.getBalance());
                transferAccountInfoDO.setMoney(money);
                transferAccountInfoVOList.add(transferAccountInfoDO.to(TransferAccountInfoVO.class));
                // 修改数据库里的余额
                this.updateByIdSelective(transferAccountInfoDO);
            } catch (Exception e) {
                log.error("查询平安银行账户余额查询异常!", e);
                throw new ParamException("查询平安银行账户余额异常！");
            }
        }
        transferAccountInfoVOList = transferAccountInfoVOList.stream()
                .sorted(Comparator.comparing(TransferAccountInfoVO::getMoney).reversed()).collect(Collectors.toList());
        return transferAccountInfoVOList;
    }


    /**
     * 根据查询参数，构建example
     *
     * @param transferAccountInfoQuery 查询参数
     * @param siteId                   所属站点id
     * @return example
     */
    private Example buildExample(TransferAccountInfoQuery transferAccountInfoQuery, String siteId) {
        Example example = new Example(TransferAccountInfoDO.class);
        example.and()
                .andEqualTo("valid", true);
        if (StrKit.isNotEmpty(siteId)) {
            example.and().andEqualTo("siteId", siteId);
        }
        if (transferAccountInfoQuery.getName() != null) {
            example.and().andLike("name", "%" + transferAccountInfoQuery.getName() + "%");
        }
        if (transferAccountInfoQuery.getPhone() != null) {
            example.and().andLike("phone", "%" + transferAccountInfoQuery.getPhone() + "%");
        }
        if (transferAccountInfoQuery.getZfbLoginId() != null) {
            example.and().andLike("zfbLoginId", "%" + transferAccountInfoQuery.getZfbLoginId() + "%");
        }
        if (transferAccountInfoQuery.getType() != null) {
            example.and().andEqualTo("type", transferAccountInfoQuery.getType());
        }
        if (CollectionKit.isNotEmpty(transferAccountInfoQuery.getTypeList())) {
            example.and().andIn("type", transferAccountInfoQuery.getTypeList());
        }
        if (transferAccountInfoQuery.getMoney() != null) {
            example.and().andEqualTo("money", transferAccountInfoQuery.getMoney());
        }
        if (transferAccountInfoQuery.getSiteName() != null) {
            example.and().andLike("siteName", "%" + transferAccountInfoQuery.getSiteName() + "%");
        }
        // 排序
        ExampleKit.setExampleOrder(example, transferAccountInfoQuery.getOrders());
        return example;
    }
}




